package com.lincoln.system.app.api;

import com.lincoln.bean.ApiCode;
import com.lincoln.bean.ApiCodeException;
import com.lincoln.bean.BaseApi;
import com.lincoln.bean.BaseSecurityApi;
import com.lincoln.entity.client.DbClient;
import com.lincoln.entity.role.DbRole;
import com.lincoln.service.RoleService;
import com.lincoln.service.TokenClientService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/client")
@CrossOrigin
public class ClientApi extends BaseSecurityApi {
    @Autowired
    TokenClientService clientService;
    @Autowired
    RoleService roleService;

    @GetMapping("/list")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode list(Integer pageNo, Integer pageSize, String name) {
        if (pageNo == null) {
            pageNo = 0;
        }
        if (pageSize == null) {
            pageSize = 10;
        }
        PageRequest pageRequest = clientService.buildPageRequest(pageNo, pageSize, Sort.Order.desc("createTime"));
        Map<String, Object> params = new HashMap<>();
        if (StringUtils.isNotEmpty(name)) {
            params.put("name", name);
        }
        Page<DbClient> page = clientService.findPage(pageRequest, params);
        return ApiCode.build(page);
    }

    @GetMapping("/{idOrName}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode info(@PathVariable String idOrName) throws Exception {
        if (StringUtils.isEmpty(idOrName)) {
            throw new ApiCodeException(10001);
        }
        DbClient client = null;
        try {
            Long id = Long.parseLong(idOrName);
            client = clientService.findById(id);
        } catch (NumberFormatException e) {
            client = clientService.findByUniqueForOne("name", idOrName);
        }
        if (client == null) {
            throw new ApiCodeException(ApiCode.build(ApiCode.FAIL, "客户端不存在!"));
        }
        return ApiCode.build(client);
    }

    @PutMapping("")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode add() throws Exception {
        String clientId = getBodyParams("clientId");
        String clientSecret = getBodyParams("clientSecret");
        String resourceIds = getBodyParams("resourceIds");
        String scope = getBodyParams("scope");
        Integer accessTokenValidity = getBodyJson().getInteger("accessTokenValidity");
        Integer refreshTokenValidity = getBodyJson().getInteger("refreshTokenValidity");

        if (StringUtils.isEmpty(clientId)) {
            return ApiCode.build(ApiCode.FAIL, "client_id can not be null!");
        }
        if (StringUtils.isEmpty(resourceIds)) {
            return ApiCode.build(ApiCode.FAIL, "resource_ids can not be null!");
        }
        if (StringUtils.isEmpty(clientSecret)) {
            return ApiCode.build(ApiCode.FAIL, "client_secret can not be null!");
        }
        if (StringUtils.isEmpty(scope)) {
            return ApiCode.build(ApiCode.FAIL, "scope can not be null!");
        }
        DbClient dbClient = clientService.findByUniqueForOne("clientId", clientId);
        if (dbClient != null) {
            throw new ApiCodeException(ApiCode.build(ApiCode.FAIL, "客户端已存在!"));
        }
        if (accessTokenValidity == null) {
            accessTokenValidity = 900;
        }
        if (refreshTokenValidity == null) {
            refreshTokenValidity = 3600;
        }
        dbClient = new DbClient();
        dbClient.setClientId(clientId);
        dbClient.setResourceIds(resourceIds);
        dbClient.setScope(scope);
        dbClient.setClientSecret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode(clientSecret));
        dbClient.setAuthorizedGrantTypes("authorization_code,password,refresh_token,implicit");
        //检测scope(英文逗号分割)
        String[] scopes = scope.split(",");
        for (String s : scopes) {
            DbRole role = roleService.findByUniqueForOne("name", s);
            if (role == null) {
                return ApiCode.build(ApiCode.FAIL, "scope is not existed!");
            }
        }
        dbClient.setAccessTokenValidity(accessTokenValidity);
        dbClient.setRefreshTokenValidity(refreshTokenValidity);
        clientService.save(dbClient);
        return ApiCode.findCode(ApiCode.SUCCESS);
    }

    @PostMapping("/{id}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode edit(@PathVariable Long id) throws Exception {
        String clientSecret = getBodyParams("clientSecret");
        if (id == null || StringUtils.isEmpty(clientSecret)) {
            throw new ApiCodeException(10001);
        }
        DbClient client = clientService.findById(id);
        if (client == null) {
            throw new ApiCodeException(10006);
        }
        if (!clientSecret.equals(client.getClientSecret())) {
            client.setClientSecret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode(clientSecret));
        }
        clientService.save(client);
        return ApiCode.findCode(ApiCode.SUCCESS);
    }
}
